/**
  ******************************************************************************
  * File Name          : ntc.c
  * Description        : This file provides code for the configuration
  *                      of the lora e22-400t22s instances.
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */
#include "bsp.h"
#include "tskcfg.h"
#include "collector.h"
#include "syscfg.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#if(COLLECTOR_USE_TYPE == COLLECTOR_USE_NTC)

#define NTC_ADC_CN_NUM                     5u
#define NTC_ADC_DATA_GROUP                 16u
#define NTC_ADC_ALL_LEN                    (NTC_ADC_CN_NUM * NTC_ADC_DATA_GROUP)

#define NTC_REFERENCE_VOLTAGE              (3.30f)
#define NTC_MEASURE_VOLTAGE(x)             ((NTC_REFERENCE_VOLTAGE*x)/4096)
#define NTC_VOLTAGE_DIVIDER_RESISTOR       (10000)

#define NTC_RESISTOR_TO_TEMPERATURE(Rt)    ((1/((log(Rt/Rp)/Bx)+(1/T2))) - Ka)

uint16_t Ntc_ArrayValue[NTC_ADC_DATA_GROUP][NTC_ADC_CN_NUM]; /* 5个通道,每个通道16组数据滤波 */

static const float Rp = 10000.0f; //10K 
static const float T2 = (273.15f+25.0f);//T2 
static const float Bx = 3950.0f;//B 
static const float Ka = 273.15f;

static const uint8_t ntc_trsmsg_err = 0xBEu;
static const uint8_t ntc_trsmsg_ok  = 0x76u;

static void dma_adc_config(void)
{
  dma_single_data_parameter_struct dma_single_data_parameter;
  
  rcu_periph_clock_enable(RCU_DMA1);
  
  dma_deinit(DMA1,DMA_CH0);
  
  dma_single_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));
  dma_single_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
  dma_single_data_parameter.memory0_addr = (uint32_t)Ntc_ArrayValue;
  dma_single_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
  dma_single_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;
  dma_single_data_parameter.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
  dma_single_data_parameter.direction = DMA_PERIPH_TO_MEMORY;
  dma_single_data_parameter.number = NTC_ADC_ALL_LEN;
  dma_single_data_parameter.priority = DMA_PRIORITY_HIGH;
  dma_single_data_mode_init(DMA1, DMA_CH0, &dma_single_data_parameter);
  
  dma_channel_subperipheral_select(DMA1, DMA_CH0, DMA_SUBPERI0);
  
  nvic_irq_enable(DMA1_Channel0_IRQn, NTC_DMA_IRQ_PRIORITY, 0);
  
  dma_interrupt_disable(DMA1, DMA_CH0, DMA_CHXCTL_HTFIE);
  dma_interrupt_enable(DMA1, DMA_CH0, DMA_CHXCTL_FTFIE);
  dma_interrupt_enable(DMA1, DMA_CH0, DMA_CHXCTL_TAEIE);
  dma_interrupt_enable(DMA1, DMA_CH0, DMA_CHXCTL_SDEIE);
  dma_interrupt_enable(DMA1, DMA_CH0, DMA_CHXFCTL_FEEIE);
  
  dma_channel_disable(DMA1, DMA_CH0);
}
#endif

static void adc_calibration(void)
{
	uint8_t timeout;
	
	timeout = 10;
	
  ADC_CTL1(ADC0) |= (uint32_t) ADC_CTL1_RSTCLB;       /* reset the selected ADC calibration registers */
  while((RESET != (ADC_CTL1(ADC0) & ADC_CTL1_RSTCLB)) && (timeout-- > 0))  /* check the RSTCLB bit state */
  {
		vTaskDelay(1);
  }
  
	timeout = 10;
	
  ADC_CTL1(ADC0) |= ADC_CTL1_CLB;                     /* enable ADC calibration process */
  while((RESET != (ADC_CTL1(ADC0) & ADC_CTL1_CLB)) && (timeout-- > 0))     /* check the CLB bit state */
  {
		vTaskDelay(1);
  }
}

void NTC_Config(void)
{
#if(COLLECTOR_USE_TYPE == COLLECTOR_USE_NTC)
  dma_adc_config();
#endif
	
  /* enable GPIOA clock */
  rcu_periph_clock_enable(RCU_GPIOA);
  /* enable ADC clock */
  rcu_periph_clock_enable(RCU_ADC0);
  /* config ADC clock */
  adc_clock_config(ADC_ADCCK_PCLK2_DIV8);

#if(COLLECTOR_USE_TYPE == COLLECTOR_USE_NTC)
  gpio_mode_set(NTC_CN1_GPIO_Port, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, NTC_CN1_Pin);
	gpio_output_options_set(NTC_CN1_GPIO_Port, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, NTC_CN1_Pin);
  
  gpio_mode_set(NTC_CN2_GPIO_Port, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, NTC_CN2_Pin);
	gpio_output_options_set(NTC_CN2_GPIO_Port, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, NTC_CN2_Pin);
  
  gpio_mode_set(NTC_CN3_GPIO_Port, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, NTC_CN3_Pin);
	gpio_output_options_set(NTC_CN3_GPIO_Port, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, NTC_CN3_Pin);
  
  gpio_mode_set(NTC_CN4_GPIO_Port, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, NTC_CN4_Pin);
	gpio_output_options_set(NTC_CN4_GPIO_Port, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, NTC_CN4_Pin);
#endif

	gpio_mode_set(POW_ADC_GPIO_Port, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, POW_ADC_Pin);
	gpio_output_options_set(POW_ADC_GPIO_Port, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, POW_ADC_Pin);
  
  /* reset ADC */
  adc_deinit();
  
  adc_resolution_config(ADC0, ADC_RESOLUTION_12B);      /* ADC位数 */
  adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT); /* ADC对齐方式 */
  adc_oversample_mode_disable(ADC0);                    /* 过采样 */
	adc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);      /* ADC同步模式配置(与其他ADC联动) */
	adc_discontinuous_mode_config(ADC0, ADC_CHANNEL_DISCON_DISABLE, 0); /* 间断模式 */
  adc_external_trigger_source_config(ADC0, ADC_ROUTINE_CHANNEL, ADC_EXTTRIG_ROUTINE_T0_CH0); /* ADC触发配置 */
  adc_external_trigger_config(ADC0, ADC_ROUTINE_CHANNEL, EXTERNAL_TRIGGER_DISABLE);
  adc_dma_request_after_last_disable(ADC0);
  adc_dma_mode_disable(ADC0);
	
#if(COLLECTOR_USE_TYPE == COLLECTOR_USE_NTC)
  adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE); /* 连续模式 */
	adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);       /* 扫描模式 */
	
	adc_channel_length_config(ADC0, ADC_ROUTINE_CHANNEL, 5U);
	
	adc_routine_channel_config(ADC0, 0U, NTC_CN1_ADC_CHANNEL, ADC_SAMPLETIME_112); /* ADC regular channel config */
  adc_routine_channel_config(ADC0, 1U, NTC_CN2_ADC_CHANNEL, ADC_SAMPLETIME_112);
  adc_routine_channel_config(ADC0, 2U, NTC_CN3_ADC_CHANNEL, ADC_SAMPLETIME_112);
  adc_routine_channel_config(ADC0, 3U, NTC_CN4_ADC_CHANNEL, ADC_SAMPLETIME_112);
  adc_routine_channel_config(ADC0, 4U, POW_ADC_ADC_CHANNEL, ADC_SAMPLETIME_112);
	
	nvic_irq_enable(ADC_IRQn, NTC_ADC_IRQ_PRIORITY, 0);
  adc_interrupt_enable(ADC0, ADC_INT_ROVF);
#else
	adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, DISABLE);
	adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);
	
	adc_channel_length_config(ADC0, ADC_ROUTINE_CHANNEL, 1U);
	
	adc_routine_channel_config(ADC0, 0U, POW_ADC_ADC_CHANNEL, ADC_SAMPLETIME_112);
	
	nvic_irq_disable(ADC_IRQn);
  adc_interrupt_disable(ADC0, ADC_INT_ROVF);
#endif

	adc_interrupt_disable(ADC0, ADC_INT_WDE);
  adc_interrupt_disable(ADC0, ADC_INT_EOC);
  adc_interrupt_disable(ADC0, ADC_INT_EOIC);
	
  adc_disable(ADC0);

//  adc_enable(ADC0);   /* enable ADC interface */
//  vTaskDelay(1U);
//  adc_calibration_enable(ADC0);  /* ADC calibration and reset calibration */
//  vTaskDelay(1U);
}

#if(COLLECTOR_USE_TYPE == COLLECTOR_USE_NTC)
void NtcPow_GetValue(volatile uint8_t *pow_flag, uint8_t *err_typ, uint8_t *err_cnt)
{
	uint32_t filter;
  uint8_t  i, j, rxmsg, avcnt, errcnt;
	int32_t  tp, av;
  float re, mv;
  BaseType_t qres;
  
	LED_NTC_GET(LED_ON);
	
  DMA_CHCNT(DMA1, DMA_CH0) = NTC_ADC_ALL_LEN;
  DMA_CHM0ADDR(DMA1, DMA_CH0) = (uint32_t)Ntc_ArrayValue;
  
  DMA_INTC0(DMA1) |= (uint32_t)(DMA_INTC_FEEIFC | DMA_INTC_SDEIFC | DMA_INTC_TAEIFC | DMA_INTC_HTFIFC | DMA_INTC_FTFIFC);  /* clear DMA_CH0 all flag */
  ADC_STAT(ADC0)  &= ~((uint32_t)(ADC_STAT_ROVF | ADC_STAT_EOIC | ADC_STAT_EOC));
  
  
  DMA_CHCTL(DMA1, DMA_CH0) |= DMA_CHXCTL_CHEN;   /* enable DMA channel */
  
  ADC_CTL1(ADC0) |= (uint32_t)(ADC_CTL1_DMA);    /* enable ADC DMA */
 
  adc_enable(ADC0);
  
  vTaskDelay(1);
  
  adc_calibration();
  
  ADC_CTL1(ADC0) |= (uint32_t)ADC_CTL1_SWRCST;   /* enable ADC routine sequence software trigger */
  
  
  qres = xQueueReceive(NTC_TrsMsg_Qhd, &rxmsg, 1000);
  
  
  adc_disable(ADC0);                             /* disable ADC */
  
  ADC_CTL1(ADC0) &= ~((uint32_t)ADC_CTL1_DMA);   /* disable ADC DMA */
  
  DMA_CHCTL(DMA1, DMA_CH0) &= ~DMA_CHXCTL_CHEN;  /* disable DMA channel */
  
  
  if((qres == pdTRUE) && (rxmsg == ntc_trsmsg_ok))
  {
		av = 0;
		avcnt = 0;
		
    for(i=0; (i<SysCfg_RunPara.lora_num)&&(i<4); i++)
    {
      filter = 0;
      
      for(j=0; j<NTC_ADC_DATA_GROUP; j++)
      {
        filter += Ntc_ArrayValue[j][i];
      }
      
      filter /= NTC_ADC_DATA_GROUP;
      
      mv = NTC_MEASURE_VOLTAGE(filter); /* 268(99.87C) ~ 3956(-35.05C) 3157(0.0C) 2048(25.0C)*/
      re = (mv * NTC_VOLTAGE_DIVIDER_RESISTOR)/(NTC_REFERENCE_VOLTAGE - mv);
      tp = (int32_t)(NTC_RESISTOR_TO_TEMPERATURE(re) * 10);
			
			if((tp >= -350)&&(tp <= 997))
			{
				Collector_LocalData.device[i].temperature = tp;
				av += Collector_LocalData.device[i].temperature;
				avcnt++;
			}
			else if(tp < -350)
			{
				Collector_LocalData.device[i].temperature = -351;
			}
			else if(tp > 997)
			{
				Collector_LocalData.device[i].temperature = 998;
			}
			else
			{
				Collector_LocalData.device[i].temperature = 999;
			}
			
			SysUsrLog("C:%u,T:%d\r\n", i, Collector_LocalData.device[i].temperature);
    }
		
		if(avcnt != 0)
		{
			Collector_LocalData.average.temperature = av/avcnt;
			
			(*err_typ) = 0;
			(*err_cnt) = 0;
			
			SysUsrLog("AVG_T:%d\r\n", Collector_LocalData.average.temperature);
		}
		else
		{
			/* error */
			(*err_typ) = 1;
			(*err_cnt)++;
		}
		
/* 12v power check */
		filter = 0;
      
		for(j=0; j<NTC_ADC_DATA_GROUP; j++)
		{
			filter += Ntc_ArrayValue[j][4];
		}
		
		if((filter/NTC_ADC_DATA_GROUP) > 1600)
		{
			(*pow_flag) = 0;
		}
		else
		{
			(*pow_flag)++;
		}
  }
	else
	{
		/* error */
		(*err_typ) = 2;
		(*err_cnt)++;
	}
	
	vTaskDelay(94);
	
	LED_NTC_GET(LED_OFF);
}
#else
void Pow_GetValue(volatile uint8_t *pow_flag)
{
  uint8_t i, timeout;
  uint32_t value;

	ADC_STAT(ADC0)  &= ~((uint32_t)(ADC_STAT_ROVF | ADC_STAT_EOIC | ADC_STAT_EOC));

	adc_enable(ADC0);
  
  vTaskDelay(1);
  
  adc_calibration();

	value = 0;

  for(i=0; i<4; i++)
  {
    timeout = 25;
		
		ADC_CTL1(ADC0) |= (uint32_t)ADC_CTL1_SWRCST;   /* enable ADC routine sequence software trigger */

    /* wait the end of conversion flag */
    while((adc_flag_get(ADC0, ADC_FLAG_EOC) == 0) &&(timeout != 0))
    {
      vTaskDelay(1);
      timeout--;
    }
    
    /* clear the end of conversion flag */
    adc_flag_clear(ADC0, ADC_FLAG_EOC);
    /* return regular channel sample value */
    value += adc_routine_data_read(ADC0);
  }
  
	adc_disable(ADC0);
	
  if((value/4) > 1600u)
  {
    (*pow_flag) = 0;
  }
  else
  {
    (*pow_flag)++;
  }
}
#endif

void DMA1_Channel0_IRQHandler(void)
{
  if(dma_interrupt_flag_get(DMA1, DMA_CH0, DMA_INT_FLAG_FTF) == SET)
  {
    dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_FTF);

#if(COLLECTOR_USE_TYPE == COLLECTOR_USE_NTC)
    if(NTC_TrsMsg_Qhd != NULL)
    {
      xQueueSendFromISR(NTC_TrsMsg_Qhd, &ntc_trsmsg_ok, NULL);
    }
#endif

  }
  
  if(dma_interrupt_flag_get(DMA1, DMA_CH0, DMA_INT_FLAG_TAE) == SET)
  {
    dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_TAE);

#if(COLLECTOR_USE_TYPE == COLLECTOR_USE_NTC)
    if(NTC_TrsMsg_Qhd != NULL)
    {
      xQueueSendFromISR(NTC_TrsMsg_Qhd, &ntc_trsmsg_err, NULL);
    }
#endif

  }
  
  if(dma_interrupt_flag_get(DMA1, DMA_CH0, DMA_INT_FLAG_SDE) == SET)
  {
    dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_SDE);

#if(COLLECTOR_USE_TYPE == COLLECTOR_USE_NTC)
    if(NTC_TrsMsg_Qhd != NULL)
    {
      xQueueSendFromISR(NTC_TrsMsg_Qhd, &ntc_trsmsg_err, NULL);
    }
#endif

  }
  
  if(dma_interrupt_flag_get(DMA1, DMA_CH0, DMA_INT_FLAG_FEE) == SET)
  {
    dma_interrupt_flag_clear(DMA1, DMA_CH0, DMA_INT_FLAG_FEE);

#if(COLLECTOR_USE_TYPE == COLLECTOR_USE_NTC)
    if(NTC_TrsMsg_Qhd != NULL)
    {
      xQueueSendFromISR(NTC_TrsMsg_Qhd, &ntc_trsmsg_err, NULL);
    }
#endif

  }
}

void ADC_IRQHandler(void)
{
  if((ADC_STAT(ADC0) & ADC_STAT_ROVF) == SET)
  {
    ADC_STAT(ADC0) &= ~((uint32_t)ADC_STAT_ROVF);

#if(COLLECTOR_USE_TYPE == COLLECTOR_USE_NTC)
    if(NTC_TrsMsg_Qhd != NULL)
    {
      xQueueSendFromISR(NTC_TrsMsg_Qhd, &ntc_trsmsg_err, NULL);
    }
#endif

  }
}
